// Package data 提供数据层的实现，包括消息存储和用户在线状态管理
package data

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	v1 "user/api/ws/v1"
	"user/internal/conf"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// ChatRepo 聊天仓库，负责消息的存储和用户在线状态管理
// 支持 MongoDB 持久化和内存在线状态
// 线程安全
type ChatRepo struct {
	Coll   *mongo.Collection // MongoDB集合（可选，不再直接用）
	mq     *RabbitMQ         // RabbitMQ 客户端
	mu     sync.RWMutex      // 读写锁，保护在线状态map
	online map[string]bool   // 用户在线状态，userID -> online
}

// NewChatRepo 创建一个新的 ChatRepo 实例，用于管理聊天消息的存储和用户在线状态。
// 参数：
//   - c: 配置信息，包含 MongoDB 相关配置，如数据库名。
//   - client: MongoDB 客户端，用于与 MongoDB 数据库进行交互。
//   - mq: RabbitMQ 客户端，用于通过 RabbitMQ 持久化消息。
//
// 返回：
//   - *ChatRepo: 新创建的 ChatRepo 实例指针。
func NewChatRepo(c *conf.Data, client *mongo.Client, mq *RabbitMQ) *ChatRepo {
	// 使用配置文件中指定的集合名称，如果没有指定则使用默认的 chat_messages
	collectionName := "chat_messages"
	if c.Mongo.Collection != "" {
		collectionName = c.Mongo.Collection
	}
	coll := client.Database(c.Mongo.Database).Collection(collectionName)
	return &ChatRepo{
		// 将 MongoDB 集合赋值给 ChatRepo 实例的 coll 字段
		Coll: coll,
		mq:   mq,
		// 初始化在线状态映射，用于记录用户的在线状态
		online: make(map[string]bool),
	}
}

// SaveMessage 通过 RabbitMQ 持久化消息
// 参数：msg - 消息内容
// 返回：error - 插入失败时返回错误
func (r *ChatRepo) SaveMessage(msg *v1.MessageItem) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return r.mq.PublishMessage(ctx, msg)
}

// GetHistory 分页获取两用户之间的历史消息（按时间倒序，最新的在前）
// 参数：
//
//	user1, user2 - 用户ID
//	page, pageSize - 分页参数
//
// 返回：
//
//	[]*v1.MessageItem - 消息列表
//	int32 - 总消息数
func (r *ChatRepo) GetHistory(user1, user2 string, page, pageSize int32) ([]*v1.MessageItem, int32) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 构建查询条件：两用户之间的所有消息
	filter := bson.M{
		"$or": []bson.M{
			{"senderid": user1, "receiverid": user2},
			{"senderid": user2, "receiverid": user1},
		},
	}

	// 设置排序：按时间戳倒序（最新的消息在前）
	opts := options.Find().SetSort(bson.D{{Key: "timestamp", Value: -1}})

	// 设置分页
	if page > 0 && pageSize > 0 {
		skip := int64((page - 1) * pageSize)
		limit := int64(pageSize)
		opts.SetSkip(skip).SetLimit(limit)
	}
	fmt.Println(filter)
	// 执行查询
	cursor, err := r.Coll.Find(ctx, filter, opts)
	if err != nil {
		log.Printf("GetHistory query error: %v", err)
		return nil, 0
	}
	defer cursor.Close(ctx)
	fmt.Println(cursor)
	// 解析结果
	var results []*v1.MessageItem
	if err := cursor.All(ctx, &results); err != nil {
		log.Printf("GetHistory cursor.All error: %v", err)
		return nil, 0
	}
	fmt.Println("GetHistory query success", results)
	// 获取总数
	total, err := r.Coll.CountDocuments(ctx, filter)
	if err != nil {
		log.Printf("GetHistory count error: %v", err)
		return results, int32(len(results))
	}

	return results, int32(total)
}

// GetHistoryByTimeRange 按时间范围获取两用户之间的历史消息
// 参数：
//
//	user1, user2 - 用户ID
//	startTime, endTime - 时间范围（Unix时间戳）
//	limit - 限制返回数量
//
// 返回：
//
//	[]*v1.MessageItem - 消息列表
func (r *ChatRepo) GetHistoryByTimeRange(user1, user2 string, startTime, endTime int64, limit int32) ([]*v1.MessageItem, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 构建查询条件
	filter := bson.M{
		"$and": []bson.M{
			{
				"$or": []bson.M{
					{"sender_id": user1, "receiver_id": user2},
					{"sender_id": user2, "receiver_id": user1},
				},
			},
			{
				"timestamp": bson.M{
					"$gte": startTime,
					"$lte": endTime,
				},
			},
		},
	}

	// 设置排序和限制
	opts := options.Find().
		SetSort(bson.D{{Key: "timestamp", Value: -1}}).
		SetLimit(int64(limit))

	cursor, err := r.Coll.Find(ctx, filter, opts)
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var results []*v1.MessageItem
	if err := cursor.All(ctx, &results); err != nil {
		return nil, err
	}

	return results, nil
}

// GetUnreadCount 获取用户未读消息数量
// 参数：
//
//	userID - 用户ID
//
// 返回：
//
//	int32 - 未读消息数量
func (r *ChatRepo) GetUnreadCount(userID string) (int32, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	filter := bson.M{
		"receiver_id": userID,
		"read":        false, // 假设有 read 字段标记是否已读
	}

	count, err := r.Coll.CountDocuments(ctx, filter)
	if err != nil {
		return 0, err
	}

	return int32(count), nil
}

// SetOnline 设置用户在线状态
// 参数：userID - 用户ID，online - 是否在线
func (r *ChatRepo) SetOnline(userID string, online bool) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.online[userID] = online
}

// IsOnline 查询用户是否在线
// 参数：userID - 用户ID
// 返回：bool - 是否在线
func (r *ChatRepo) IsOnline(userID string) bool {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.online[userID]
}

func chatKey(u1, u2 string) string {
	if u1 < u2 {
		return u1 + "|" + u2
	}
	return u2 + "|" + u1
}
